/*
* ============================================================================
*  Name        : sea_timer.cpp
*  Part of     : Finite state machine framework 
*  Description : State machine timer implementation
*  Version     : %version: %
*  
*
* ============================================================================
*/
#include "sea.h"
#include "sea_iterator.h"
#include "sea_queue.h"
#include "sea_engine.h"
#include "sea_timer.h"

/**
 * @file sea_timer.cpp
 *
 * @ingroup StateMachineFramework
 */
using namespace sea;

// -------------------------------------------------------------------------------------------------
// Ctor
// -------------------------------------------------------------------------------------------------
Timer::Timer(
    int heart_beat_rate /* = 0 */,
    int heart_beats /* = 0 */,
    Callback callback /* = NULL */,
    void* callback_param /* = NULL */ ) :
        m_state( NOT_ACTIVE ),
        m_handle( NULL ), 
        m_heart_beat_rate( heart_beat_rate ),
        m_heart_beats( heart_beats ),
        m_heart_beats_counter( 0 ),
        m_start_time_stamp( 0 ),
        m_callback( callback ),
        m_data( callback_param )
{
}

// -------------------------------------------------------------------------------------------------
// Ctor
// -------------------------------------------------------------------------------------------------
Timer::Timer(
    StateMachine* handle, 
    int heart_beat_rate /* = 0 */,
    int heart_beats /* = 0 */,
    void* event_data /* = NULL */,
    EventId heart_beat_event_id /* = NULL */,
    EventId last_heart_beat_event_id /* = NULL */ ) :
        m_state( NOT_ACTIVE ),
        m_handle( handle ), 
        m_heart_beat_rate( heart_beat_rate ),
        m_heart_beats( heart_beats ),
        m_heart_beats_counter( 0 ),
        m_start_time_stamp( 0 ),
        m_callback( NULL ),
        m_data( event_data ),
        m_heart_beat_event_id( heart_beat_event_id ),
        m_last_heart_beat_event_id( last_heart_beat_event_id )
{
    if( m_heart_beat_rate > 0 )
    {
        // adopt( ) does not add reference to the object
        m_event.adopt( NEW Event( handle, heart_beat_event_id, event_data, false ) );
        ASSERT_DEBUG( m_event != NULL );
    }
}

// -------------------------------------------------------------------------------------------------
// Start timer
// -------------------------------------------------------------------------------------------------
void Timer::start( )
{
    OsMutex::Scoped safe( &m_lock );

    if( m_heart_beat_rate > 0 )
    {
        m_state = ACTIVE;
        Engine::engine( )->timer_server( )->start_timer( this ); 
    }
}

// -------------------------------------------------------------------------------------------------
// Stop timer
// -------------------------------------------------------------------------------------------------
void Timer::stop( )
{
    OsMutex::Scoped safe( &m_lock );

    if( m_heart_beat_rate > 0 )
    {
        m_state = NOT_ACTIVE;
        ASSERT_DEBUG( m_event != NULL );
        Engine::engine( )->timer_server( )->stop_timer( this );
        m_event->set_event_id( m_heart_beat_event_id );
    }
}

// -------------------------------------------------------------------------------------------------
// Reset timer
// -------------------------------------------------------------------------------------------------
void Timer::reset( )
{
    OsMutex::Scoped safe( &m_lock );

    stop( );
    m_heart_beats_counter = 0;
    m_start_time_stamp = 0;
}

// -------------------------------------------------------------------------------------------------
// Set owner state machine
// -------------------------------------------------------------------------------------------------
void Timer::forget_state_machine( )
{
    OsMutex::Scoped safe( &m_lock );
    m_handle = NULL;
    m_event = NULL;
}

// -------------------------------------------------------------------------------------------------
// Invoke callback
// -------------------------------------------------------------------------------------------------
void Timer::invoke_callback( )
{
    OsMutex::Scoped safe( &m_lock );

    if ( m_state != TO_BE_FIRED )
    {
        return;
    }

    if ( m_callback ) 
    {
        ( *m_callback )( m_data );
        return;
    }

    if ( m_handle == NULL )
    {
        return;
    }

    if ( m_heart_beats > 0 ) 
    {
        m_heart_beats_counter++;
        if ( m_heart_beats == m_heart_beats_counter ) 
        {
            m_event->set_event_id( m_last_heart_beat_event_id );
            m_handle->push_event( m_event.get( ) );
            return;
        }
    }

    m_handle->push_event( m_event.get( ) );
    start( );
}

// -------------------------------------------------------------------------------------------------
// Set new heartbeat rate
// -------------------------------------------------------------------------------------------------
void Timer::set_heart_beat_rate( int heart_beat_rate_ms ) 
{
    OsMutex::Scoped safe( &m_lock );

    if( heart_beat_rate_ms > 0 && m_heart_beat_rate <= 0 )
    {
        if ( m_handle == NULL )
        {
            return;
        }

        m_event.adopt( NEW Event( m_handle.get( ), m_heart_beat_event_id, m_data, false ) );
        ASSERT_DEBUG( m_event != NULL );
    }

    m_heart_beat_rate = heart_beat_rate_ms; 
}

// -------------------------------------------------------------------------------------------------
